package cn.moefly.common.utils;

import com.univocity.parsers.annotations.Parsed;
import com.univocity.parsers.common.processor.BeanWriterProcessor;
import com.univocity.parsers.csv.CsvWriter;
import com.univocity.parsers.csv.CsvWriterSettings;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;

public abstract class FileUtils {
    /**
     *
     * @author:Zheng Chuansi
     * @Description: download single file.
     * @time:2016-11-25 8:49:44
     * @param response
     * @param filePath
     */
    public static void download(HttpServletResponse response, String filePath) throws IOException {
        File file = new File(filePath);
        /*Get the file to download*/
        InputStream fis = new BufferedInputStream(new FileInputStream(file));
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();
        //clear response
        response.reset();
        OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
        response.setContentType("application/x-msdownload");
        response.setHeader("Content-Disposition",
                "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        toClient.write(buffer);
        toClient.flush();
        toClient.close();
    }


    /**
     * @param beanList a list of export bean, which Use annotations {@link Parsed} appropriately.
     */
    public static String exportCsv(String fileName,List beanList) {
        var tmpFolderPath = SystemEnvironmentUtils.systemTempFolder();
        return exportCsv(beanList,null,null,new File(tmpFolderPath +fileName));
    }


    /**
     * @param beanList a list of export bean, which Use annotations {@link Parsed} appropriately
     */
    public static String exportCsv(File output,List beanList){
        return exportCsv(beanList,null,null,output);
    }


    /**
     * @param beanList a list of export bean, which Use annotations {@link Parsed} appropriately
     */
    public static String exportCsv(List beanList, String[] headers, String[] commentBeforeHead, File file) {
        if (beanList.isEmpty()){throw new IllegalArgumentException();}

        CsvWriterSettings csvWriterSettings = new CsvWriterSettings();
        csvWriterSettings.setHeaderWritingEnabled(Boolean.TRUE);

        //use headers[] or use fieldName as headers
        Class clazz = beanList.get(0).getClass();
        if (headers == null){
            Field[] fields = clazz.getDeclaredFields();
            var colNames = new LinkedList<String>();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Parsed.class)){
                    Parsed parsed = field.getAnnotation(Parsed.class);
                    String[] colNamesDefOnAnno = parsed.field();
                    // use field define in Annotation if exist.
                    if (colNamesDefOnAnno.length > 0){
                        colNames.add(colNamesDefOnAnno[0]);
                    }else {
                        colNames.add(field.getName());
                    }
                }
            }
            headers = colNames.toArray(new String[colNames.size()]);

        }
        csvWriterSettings.setHeaders(headers);

        //comment
        csvWriterSettings.setRowWriterProcessor(new BeanWriterProcessor<>(clazz));

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
        } catch (FileNotFoundException ignored) {
            // the file will be touch when output
        }
        CsvWriter writer = new CsvWriter(fos, Charset.forName("utf-8"), csvWriterSettings);
        if (commentBeforeHead != null){
            for (int i = 0, commentBeforeHeadLength = commentBeforeHead.length; i < commentBeforeHeadLength; i++) {
                String s = commentBeforeHead[i];
                writer.commentRow(s);
            }
        }

        beanList.forEach(writer::processRecord);
        writer.close();

        return file.getAbsolutePath();
    }

}
